
#include "RtBase.h"
/************************************************************
 *    uuencode/decode functions
 ************************************************************/
//
//  Taken from NCSA HTTP and wwwlib.
//
//  NOTE: These conform to RFC1113, which is slightly different then the Unix
//        uuencode and uudecode!
//

const int pr2six[256]={
    64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
    64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,62,64,64,64,63,
    52,53,54,55,56,57,58,59,60,61,64,64,64,64,64,64,64,0,1,2,3,4,5,6,7,8,9,
    10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,64,64,64,64,64,64,26,27,
    28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,
    64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
    64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
    64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
    64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
    64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
    64,64,64,64,64,64,64,64,64,64,64,64,64
};

char six2pr[64] = {
    'A','B','C','D','E','F','G','H','I','J','K','L','M',
    'N','O','P','Q','R','S','T','U','V','W','X','Y','Z',
    'a','b','c','d','e','f','g','h','i','j','k','l','m',
    'n','o','p','q','r','s','t','u','v','w','x','y','z',
    '0','1','2','3','4','5','6','7','8','9','+','/'
};


void RtBase64Decode(const char *bufcoded, CRtString &sbDest)
{
    int nbytesdecoded;
    const char *bufin = bufcoded;
    unsigned char *bufout;
    int nprbytes;

    /* Strip leading whitespace. */

    while(*bufcoded==' ' || *bufcoded == '\t') bufcoded++;

    /* Figure out how many characters are in the input buffer.
     * If this would decode into more bytes than would fit into
     * the output buffer, adjust the number of input bytes downwards.
     */
    bufin = bufcoded;
    while(pr2six[(int)*(bufin++)] <= 63){}
    nprbytes = bufin - bufcoded - 1;
    nbytesdecoded = ((nprbytes+3)/4) * 3;

	sbDest.resize(0);
	sbDest.resize(nbytesdecoded);
    bufout = reinterpret_cast<unsigned char *>(const_cast<char*>(sbDest.c_str()));
    bufin = bufcoded;

    while (nprbytes > 0) {
        *(bufout++) =
            (unsigned char) (pr2six[(int)*bufin] << 2 | pr2six[(int)bufin[1]] >> 4);
        *(bufout++) =
            (unsigned char) (pr2six[(int)bufin[1]] << 4 | pr2six[(int)bufin[2]] >> 2);
        *(bufout++) =
            (unsigned char) (pr2six[(int)bufin[2]] << 6 | pr2six[(int)bufin[3]]);
        bufin += 4;
        nprbytes -= 4;
    }

    if(nprbytes & 03) {
        if(pr2six[(int)bufin[-2]] > 63)
            nbytesdecoded -= 2;
        else
            nbytesdecoded -= 1;
		sbDest.resize(nbytesdecoded);
    }
}

void RtBase64Encode(const unsigned char *bufin, DWORD nbytes, CRtString &sbDest)
{
   unsigned char *outptr;
   unsigned int i;

   //
   //  Resize the buffer to 133% of the incoming data
   //
   sbDest.resize(0);
   sbDest.resize(nbytes + ((nbytes + 3) / 3) + 4);
   outptr = reinterpret_cast<unsigned char *>(const_cast<char*>(sbDest.c_str()));

   for (i=0; i<nbytes; i += 3) {
      *(outptr++) = six2pr[*bufin >> 2];            /* c1 */
      *(outptr++) = six2pr[((*bufin << 4) & 060) | ((bufin[1] >> 4) & 017)]; /*c2*/
      *(outptr++) = six2pr[((bufin[1] << 2) & 074) | ((bufin[2] >> 6) & 03)];/*c3*/
      *(outptr++) = six2pr[bufin[2] & 077];         /* c4 */

      bufin += 3;
   }

   /* If nbytes was not a multiple of 3, then we have encoded too
    * many characters.  Adjust appropriately.
    */
   if(i == nbytes+1) {
      /* There were only 2 bytes in that last group */
      outptr[-1] = '=';
   } else if(i == nbytes+2) {
      /* There was only 1 byte in that last group */
      outptr[-1] = '=';
      outptr[-2] = '=';
   }

   *(outptr++) = '\0';

   size_t len = outptr - 1 -
	   reinterpret_cast<unsigned char *>(const_cast<char*>(sbDest.c_str()));
   RT_ASSERTE(len <= sbDest.length());
   if (len < sbDest.length())
	   sbDest.resize(len);
}

const char * rt_strcaserstr(const char *big, const char *little)
{
    const char *p;
    size_t ll;

    if( ((const char *)0 == big) || ((const char *)0 == little) ) return (char *)0;
    if( ((char)0 == *big) || ((char)0 == *little) ) return NULL;

    ll = strlen(little);
    p = &big[ strlen(big) - ll ];
    if( p < big ) return NULL;

    for( ; p >= big; p-- )
        /* obvious improvement available here */
            if( 0 == strncasecmp(p, little, ll) )
                return (char *)p;

    return NULL;
}

DWORD RtGetLocalIP()
{
	DWORD rvAddr = INADDR_ANY;
	char buffer[256];
	if(gethostname(buffer, sizeof(buffer)) == 0) 
	{
		struct hostent* host = gethostbyname(buffer);
		if (host)
		{
			memcpy(&rvAddr, host->h_addr, host->h_length);
		}
	}
	return rvAddr;
}

#ifdef RT_WIN32

#include <objbase.h>

struct RtThreadComInitNum 
{
	RT_THREAD_ID m_threadID;
	WORD m_comInitNum;

	RtThreadComInitNum(RT_THREAD_ID threadID, WORD num)
		: m_threadID(threadID)
		, m_comInitNum(num)
	{}
};

typedef std::list<RtThreadComInitNum> RtThreadComInitNumList;
RtThreadComInitNumList g_threadComInitNums;
CRtMutexThread g_mutexComInit;

RtResult RtCoInitialize()
{
	RT_THREAD_ID threadID = CRtThreadManager::Instance()->GetThreadSelfId();

	CRtMutexGuardT<CRtMutexThread> mutexGuard(g_mutexComInit);
	for (RtThreadComInitNumList::iterator it=g_threadComInitNums.begin(); it!=g_threadComInitNums.end(); ++it)
	{
		if (it->m_threadID == threadID)
		{
			RT_ASSERTE(it->m_comInitNum > 0);
			++ (it->m_comInitNum);
			return RT_OK;
		}
	}

	HRESULT rv = ::CoInitialize(NULL);
	if (rv == S_OK)
	{
		g_threadComInitNums.push_back(RtThreadComInitNum(threadID, 1));
		return RT_OK;
	}

	RT_WARNING_TRACE("::RtCoInitialize, CoInitialize failed! rv="<<rv<<" threadID="<<threadID);
	return RT_ERROR_FAILURE;
}

void RtCoUninitialize()
{
	RT_THREAD_ID threadID = CRtThreadManager::Instance()->GetThreadSelfId();

	CRtMutexGuardT<CRtMutexThread> mutexGuard(g_mutexComInit);
	for (RtThreadComInitNumList::iterator it=g_threadComInitNums.begin(); it!=g_threadComInitNums.end(); ++it)
	{
		if (it->m_threadID == threadID)
		{
			RT_ASSERTE(it->m_comInitNum > 0);
			if ( (--(it->m_comInitNum)) == 0 )
			{
				::CoUninitialize();
				g_threadComInitNums.erase(it);
			}
			return;
		}
	}

	RT_WARNING_TRACE("::RtCoUninitialize, COM initialization record not found! threadID="<<threadID);
}

#else

void Sleep(DWORD dwMilliSecond)
{
	struct timespec ts, rmts;
	
	ts.tv_sec = dwMilliSecond/1000;
	ts.tv_nsec = (dwMilliSecond%1000)*1000000;
	while(1)
	{
		int ret = nanosleep(&ts, &rmts);
		if(ret == 0) 
			break;
		if(ret == -1 && errno == EINTR)
		{
			ts = rmts;
		}
		else
		{
			RT_ASSERTE(FALSE);
		}
	}
}

#endif // RT_WIN32

LONGLONG GetTickCountEx()
{
#ifdef RT_WIN32
	return GetTickCount();
#else
	return CRtTimeValue::GetTimeOfDay().GetTotalInMsec();
#endif
}

#include "RtHashMapT.h"

_STLP_BEGIN_NAMESPACE

/*
# define __PRIME_LIST_BODY { \
	53ul,         97ul,         193ul,       389ul,       769ul,      \
	1543ul,       3079ul,       6151ul,      12289ul,     24593ul,    \
	49157ul,      98317ul,      196613ul,    393241ul,    786433ul,   \
	1572869ul,    3145739ul,    6291469ul,   12582917ul,  25165843ul, \
	50331653ul,   100663319ul,  201326611ul, 402653189ul, 805306457ul,\
	1610612741ul, 3221225473ul, 4294967291ul  \
}
const size_t CRtPrimeList::s_primes[__stl_num_primes] = __PRIME_LIST_BODY;
*/
# undef __PRIME_LIST_BODY

_STLP_END_NAMESPACE

